/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <vector>

#include "command_apdu.h"

#include "command_apdu_test_helper.h"

using namespace testing;

namespace OHOS {
namespace SeBaseServices {
namespace UnitTest {
TEST(CommandApduTest, CreateCommandApduWithInvalidHeader)
{
    ApduCommandHeader *header = nullptr;
    CommandApdu *cmd = CommandApduTestHelper(header, nullptr, 0, 0).Get();

    EXPECT_EQ(cmd, nullptr);
}

TEST(CommandApduTest, CreateCommandApduWithCaseOne)
{
    ApduCommandHeader header = {0x00, 0xa4, 0x04, 0x00};
    CommandApduTestHelper helper(&header, nullptr, 0, 0);
    CommandApdu *cmd = helper.Get();

    ASSERT_NE(cmd, nullptr);

    uint32_t bufferSize;
    const uint8_t *buff = GetApduCommandBuffer(cmd, &bufferSize);
    ASSERT_NE(buff, nullptr);

    EXPECT_EQ(bufferSize, 4);

    EXPECT_THAT(std::vector<uint8_t>(buff, buff + bufferSize), ElementsAreArray({0x00, 0xa4, 0x04, 0x00}));
}

TEST(CommandApduTest, CreateCommandApduWithCaseTwoShort0)
{
    ApduCommandHeader header = {0x00, 0xa4, 0x04, 0x00};
    CommandApduTestHelper helper(&header, nullptr, 0, 100);
    CommandApdu *cmd = helper.Get();

    ASSERT_NE(cmd, nullptr);

    uint32_t bufferSize;
    const uint8_t *buff = GetApduCommandBuffer(cmd, &bufferSize);
    ASSERT_NE(buff, nullptr);

    EXPECT_EQ(bufferSize, 5); // In case 2s, The short Le field consists of C(5) encoding Ne from 1 to 256

    EXPECT_THAT(std::vector<uint8_t>(buff, buff + bufferSize), ElementsAreArray({0x00, 0xa4, 0x04, 0x00, 0x64}));
}

TEST(CommandApduTest, CreateCommandApduWithCaseTwoShort1)
{
    ApduCommandHeader header = {0x00, 0xa4, 0x04, 0x00};
    CommandApduTestHelper helper(&header, nullptr, 0, 256);
    CommandApdu *cmd = helper.Get();

    ASSERT_NE(cmd, nullptr);

    uint32_t bufferSize;
    const uint8_t *buff = GetApduCommandBuffer(cmd, &bufferSize);
    ASSERT_NE(buff, nullptr);

    EXPECT_EQ(bufferSize, 5); // In case 2s, The short Le field consists of C(5) encoding Ne from 1 to 256

    EXPECT_THAT(std::vector<uint8_t>(buff, buff + bufferSize), ElementsAreArray({0x00, 0xa4, 0x04, 0x00, 0x00}));
}

TEST(CommandApduTest, CreateCommandApduWithCaseTwoShort2)
{
    ApduCommandHeader header = {0x00, 0xa4, 0x04, 0x00};

    CommandApdu *cmd = CreateCommandApdu(&header, nullptr, 0, 0x512);

    EXPECT_EQ(cmd, nullptr);
}

TEST(CommandApduTest, CreateCommandApduWithCaseThreeShort0)
{
    ApduCommandHeader header = {0x00, 0xa4, 0x04, 0x00};
    const uint8_t data[] = {0x00, 0x01, 0x02, 0x03};
    CommandApduTestHelper helper(&header, data, sizeof(data) / sizeof(uint8_t), 0);
    CommandApdu *cmd = helper.Get();

    ASSERT_NE(cmd, nullptr);

    uint32_t bufferSize;
    const uint8_t *buff = GetApduCommandBuffer(cmd, &bufferSize);
    ASSERT_NE(buff, nullptr);

    EXPECT_EQ(bufferSize, 9);

    EXPECT_THAT(std::vector<uint8_t>(buff, buff + bufferSize),
        ElementsAreArray({0x00, 0xa4, 0x04, 0x00, 0x04, 0x00, 0x01, 0x02, 0x03}));
}

TEST(CommandApduTest, CreateCommandApduWithCaseFourShort0)
{
    ApduCommandHeader header = {0x00, 0xa4, 0x04, 0x00};
    const uint8_t data[] = {0x00, 0x01, 0x02, 0x03};
    CommandApduTestHelper helper(&header, data, sizeof(data) / sizeof(uint8_t), 256);

    CommandApdu *cmd = helper.Get();

    ASSERT_NE(cmd, nullptr);

    uint32_t bufferSize;
    const uint8_t *buff = GetApduCommandBuffer(cmd, &bufferSize);
    ASSERT_NE(buff, nullptr);

    EXPECT_EQ(bufferSize, 10);

    EXPECT_THAT(std::vector<uint8_t>(buff, buff + bufferSize),
        ElementsAreArray({0x00, 0xa4, 0x04, 0x00, 0x04, 0x00, 0x01, 0x02, 0x03, 00}));
}

TEST(CommandApduTest, CreateCommandApduWithCaseFourShort1)
{
    ApduCommandHeader header = {0x00, 0xa4, 0x04, 0x00};

    const uint8_t data[] = {0x00, 0x01, 0x02, 0x03};
    CommandApduTestHelper helper(&header, data, sizeof(data) / sizeof(uint8_t), 100);
    CommandApdu *cmd = helper.Get();

    ASSERT_NE(cmd, nullptr);

    uint32_t bufferSize;
    const uint8_t *buff = GetApduCommandBuffer(cmd, &bufferSize);
    ASSERT_NE(buff, nullptr);

    EXPECT_EQ(bufferSize, 10);

    EXPECT_THAT(std::vector<uint8_t>(buff, buff + bufferSize),
        ElementsAreArray({0x00, 0xa4, 0x04, 0x00, 0x04, 0x00, 0x01, 0x02, 0x03, 0x64}));
}

TEST(CommandApduTest, GetApduCommandBufferCaseNullptr)
{
    {
        auto *buff = GetApduCommandBuffer(nullptr, nullptr);
        ASSERT_EQ(buff, nullptr);
    }

    {
        ApduCommandHeader header = {0x00, 0xa4, 0x04, 0x00};
        const uint8_t data[] = {0x00, 0x01, 0x02, 0x03};
        CommandApduTestHelper helper(&header, data, sizeof(data) / sizeof(uint8_t), 100);

        auto *buff = GetApduCommandBuffer(helper.Get(), nullptr);
        ASSERT_EQ(buff, nullptr);
    }

    DestroyCommandApdu(nullptr);
}

} // namespace UnitTest
} // namespace SeBaseServices
} // namespace OHOS